#pragma once
#include "MeasureLine.h"
#include "MeasureTool.h"

class CMeasureItem
{
  friend class boost::serialization::access;

public:
  enum MeasureType {
    kLineLineDistance           = 0,
    kLineLineAngle              = 1,
    kLineLineIntersection       = 2,
    kPointPointDistance         = 3,
    kPointLineDistance          = 4,
    kModelAbsolutePosition      = 5,
    kModelRelativePosition      = 6,
    kArcRadius                  = 7,
    kArcArcCenterDistance       = 8,
    kArcArcDistance             = 9,
    kArcLineCenterDistance      = 10,
    kArcLineNearDistance        = 11,
    kArcLineFarDistance         = 12,
    kArcCenter                  = 13,
    kArcLineIntersection        = 14,
    kArcLength                  = 15,
    kArcDegree                  = 16,
    kBoxEdgeBoxEdgeDistance     = 17,
    kBoxEdgeEdgeCenter          = 18,
    kBoxEdgePosition            = 19,
    kChamferWidth               = 20,
    kProfile                    = 21,
    kOffset                     = 22,
    kDummyItem                  = 23,
    kLinePosition               = 24,
    kArcEdgePosition            = 25,
    kArcDiameter                = 26,

    kMeasureTypeButt
  };

  static tstring MeasureTypeToString(int measureType);
  static bool IsMeasureTypeSingle(int measureType);
  static int GetNumParams(int measureType);

public:
  static double DistancePL(double x, double y, int iL, const CMeasureLine* l);
  static double DistanceLL(int iL0, const CMeasureLine* l0, int iL1, const CMeasureLine* l1);
  static double AngleLL(int iL0, const CMeasureLine* l0, int iL1, const CMeasureLine* l1);

public:
  CMeasureItem(void);
  CMeasureItem(const tstring& name, int type, const tstring& first);
  CMeasureItem(const tstring& name, int type, const tstring& first,
    const tstring& second, const tstring& third);
  ~CMeasureItem(void);

public:
  void Init(void);
  void Reset(void);
  void Process(void);
  bool IsIntermediatePoint(void) const;
  const std::string& GetValueString(void) { return val_string_; }
  void Draw(BOOL eraseBackground, BOOL bFlush);
  void GetTools(std::vector<CMeasureTool> &tools);
  void GetToolType(int &firstType, int &secondType, int &thirdType);
  void ChangeToolName(int elemType, const tstring& oldName, const tstring& newName);

private:
  void DoNGOK(void);
  void ProcessLinePos(void);
  void ProcessLLDist(void);
  void ProcessLLAngle(void);
  void ProcessLLIntersection(void);
  void ProcessPPDist(void);
  void ProcessPLDist(void);
  void ProcessModelAbsPos(void);
  void ProcessModelRelPos(void);
  void ProcessArcRadius(void);
  void ProcessArcDiameter(void);
  void ProcessAACenterDist(void);
  void ProcessAADist(void);
  void ProcessALCenterDist(void);
  void ProcessALNearDist(void);
  void ProcessALFarDist(void);
  void ProcessArcCenter(void);
  void ProcessALIntersection(void);
  void ProcessArcLength(void);
  void ProcessArcDegree(void);
  void ProcessArcEdgePos(void);
  void ProcessBoxEdgeBoxEdgeDist(void);
  void ProcessBoxEdgeEdgeCenter(void);
  void ProcessBoxEdgePos(void);
  void ProcessChamferWidth(void);
  void ProcessProfile(void);
  void ProcessOffset(void);
  void ProcessDummy(void);

private:
  void DrawLinePos(void);
  void DrawLLDist(void);
  void DrawLLAngle(void);
  void DrawLLIntersection(void);
  void DrawPPDist(void);
  void DrawPLDist(void);
  void DrawModelAbsPos(void);
  void DrawModelRelPos(void);
  void DrawArcRadius(void);
  void DrawArcDiameter(void);
  void DrawAACenterDist(void);
  void DrawAADist(void);
  void DrawALCenterDist(void);
  void DrawALNearDist(void);
  void DrawALFarDist(void);
  void DrawArcCenter(void);
  void DrawALIntersection(void);
  void DrawArcLength(void);
  void DrawArcDegree(void);
  void DrawArcEdgePos(void);
  void DrawBoxEdgeBoxEdgeDist(void);
  void DrawBoxEdgeEdgeCenter(void);
  void DrawBoxEdgePos(void);
  void DrawChamferWidth(void);
  void DrawProfile(void);
  void DrawOffset(void);
  void DrawDummy(void);

private:
  void ToolLinePos(std::vector<CMeasureTool> &tools);
  void ToolLLDist(std::vector<CMeasureTool> &tools);
  void ToolLLAngle(std::vector<CMeasureTool> &tools);
  void ToolLLIntersection(std::vector<CMeasureTool> &tools);
  void ToolPPDist(std::vector<CMeasureTool> &tools);
  void ToolPLDist(std::vector<CMeasureTool> &tools);
  void ToolModelAbsPos(std::vector<CMeasureTool> &tools);
  void ToolModelRelPos(std::vector<CMeasureTool> &tools);
  void ToolArcRadius(std::vector<CMeasureTool> &tools);
  void ToolArcDiameter(std::vector<CMeasureTool> &tools);
  void ToolAACenterDist(std::vector<CMeasureTool> &tools);
  void ToolAADist(std::vector<CMeasureTool> &tools);
  void ToolALCenterDist(std::vector<CMeasureTool> &tools);
  void ToolALNearDist(std::vector<CMeasureTool> &tools);
  void ToolALFarDist(std::vector<CMeasureTool> &tools);
  void ToolArcCenter(std::vector<CMeasureTool> &tools);
  void ToolALIntersection(std::vector<CMeasureTool> &tools);
  void ToolArcLength(std::vector<CMeasureTool> &tools);
  void ToolArcDegree(std::vector<CMeasureTool> &tools);
  void ToolArcEdgePos(std::vector<CMeasureTool> &tools);
  void ToolBoxEdgeBoxEdgeDist(std::vector<CMeasureTool> &tools);
  void ToolBoxEdgeEdgeCenter(std::vector<CMeasureTool> &tools);
  void ToolBoxEdgePos(std::vector<CMeasureTool> &tools);
  void ToolChamferWidth(std::vector<CMeasureTool> &tools);
  void ToolProfile(std::vector<CMeasureTool> &tools);
  void ToolOffset(std::vector<CMeasureTool> &tools);
  void ToolDummy(std::vector<CMeasureTool> &tools);

public:
  const tstring& Name(void) const { return name_; }
  void SetName(const tstring& val);

  const tstring& CmdName(void) const { return cmd_name_; }
  void SetCmdName(const tstring& val) { cmd_name_ = val; }

  const tstring& First(void) const { return first_; }
  void SetFirst(const tstring& val) { first_ = val; }

  const tstring& Second(void) const { return second_; }
  void SetSecond(const tstring& val) { second_ = val; }

  const tstring& Third(void) const { return third_; }
  void SetThird(const tstring& val) { third_ = val; }

  int Type(void) const { return type_; }
  void SetType(int val) { type_ = val; }
  tstring TypeString(void) const { return MeasureTypeToString(type_); }

  int intermediate(void) const { return intermediate_; }
  void set_intermediate(int val) { intermediate_ = val; }

  int index_i(void) const { return i_; }
  void set_index_i(int val) { i_ = val; }

  int index_j(void) const { return j_; }
  void set_index_j(int val) { j_ = val; }

  int index_k(void) const { return k_; }
  void set_index_k(int val) { k_ = val; }

  double coefficient(void) const { return coefficient_; }
  void set_coefficient(double val) { coefficient_ = val; }

  double offset(void) const { return offset_; }
  void set_offset(double val) { offset_ = val; }

  double distance(void) const { return distance_; }
  void set_distance(double val) { distance_ = val; }

  double target_value(void) const { return target_value_; }
  void set_target_value(double val) { target_value_ = val; }

  double tolerance_upper(void) const { return tolerance_upper_; }
  void set_tolerance_upper(double val) { tolerance_upper_ = val; }

  double tolerance_lower(void) const { return tolerance_lower_; }
  void set_tolerance_lower(double val) { tolerance_lower_ = val; }

  int disp_index(void) const { return disp_index_; }
  void set_disp_index(int val) { disp_index_ = val; }

  bool ok(void) const { return ok_; }
  double point_x(void) const { return point_x_; }
  double point_y(void) const { return point_y_; }
  double angle(void) const { return angle_; }
  double result(void) const { return result_; }

private:
  bool    ok_;
  int     disp_index_;
  double  point_x_;
  double  point_y_;
  double  angle_;
  double  result_;
  std::string val_string_;

private:
  tstring name_;
  tstring cmd_name_;
  tstring first_;
  tstring second_;
  tstring third_;
  int     type_;
  int     intermediate_;
  int     enabled_;
  int     i_;
  int     j_;
  int     k_;

  double coefficient_;
  double offset_;
  double distance_;

  double target_value_;
  double tolerance_upper_;
  double tolerance_lower_;

  template<class Archive>
  void serialize(Archive &ar, const unsigned int version)
  {
    using boost::serialization::make_nvp;
    ar & make_nvp("name",             name_);
    ar & make_nvp("cmd_name",         cmd_name_);
    ar & make_nvp("first",            first_);
    ar & make_nvp("second",           second_);
    ar & make_nvp("third",            third_);
    ar & make_nvp("type",             type_);
    ar & make_nvp("intermediate",     intermediate_);
    ar & make_nvp("enabled",          enabled_);
    ar & make_nvp("index_i",          i_);
    ar & make_nvp("index_j",          j_);
    ar & make_nvp("index_k",          k_);
    ar & make_nvp("coefficient",      coefficient_);
    ar & make_nvp("offset",           offset_);
    ar & make_nvp("distance",         distance_);
    ar & make_nvp("target_value",     target_value_);
    ar & make_nvp("tolerance_upper",  tolerance_upper_);
    ar & make_nvp("tolerance_lower",  tolerance_lower_);
  }
};

